home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 219_01 / a65util.c < prev    next >
Text File  |  1989-01-11  |  13KB  |  493 lines

  1. /*
  2.     HEADER:        CUG219;
  3.     TITLE:        6502 Cross-Assembler (Portable);
  4.     FILENAME:    A65UTIL.C;
  5.     VERSION:    0.1;
  6.     DATE:        08/27/1988;
  7.  
  8.     DESCRIPTION:    "This program lets you use your computer to assemble
  9.             code for the MOS Technology 6502 microprocessors.  The
  10.             program is written in portable C rather than BDS C.
  11.             All assembler features are supported except relocation
  12.             linkage, and macros.";
  13.  
  14.     KEYWORDS:    Software Development, Assemblers, Cross-Assemblers,
  15.             MOS Technology, 6502;
  16.  
  17.     SYSTEM:        CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
  18.     COMPILERS:    Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
  19.             Lattice C, Microsoft C,    QNIX C;
  20.  
  21.     WARNINGS:    "This program is written in as portable C as possible.
  22.             A port to BDS C would be extremely difficult, but see
  23.             volume CUG113.  A port to Toolworks C is untried."
  24.  
  25.     AUTHORS:    William C. Colley III;
  26. */
  27.  
  28. /*
  29.               6502 Cross-Assembler in Portable C
  30.  
  31.            Copyright (c) 1986 William C. Colley, III
  32.  
  33. Revision History:
  34.  
  35. Ver    Date        Description
  36.  
  37. 0.0    NOV 1986    Derived from my 6800/6801 cross-assembler.  WCC3.
  38.  
  39. 0.1    AUG 1988    Fixed a bug in the command line parser that puts it
  40.             into a VERY long loop if the user types a command line
  41.             like "A65 FILE.ASM -L".  WCC3 per Alex Cameron.
  42.  
  43. This module contains the following utility packages:
  44.  
  45.     1)  symbol table building and searching
  46.  
  47.     2)  opcode and operator table searching
  48.  
  49.     3)  listing file output
  50.  
  51.     4)  hex file output
  52.  
  53.     5)  error flagging
  54. */
  55.  
  56. /*  Get global goodies:  */
  57.  
  58. #include "a65.h"
  59.  
  60. /*  Make sure that MSDOS compilers using the large memory model know    */
  61. /*  that calloc() returns pointer to char as an MSDOS far pointer is    */
  62. /*  NOT compatible with the int type as is usually the case.        */
  63.  
  64. char *calloc();
  65.  
  66. /*  Get access to global mailboxes defined in A65.C:            */
  67.  
  68. extern char errcode, line[], title[];
  69. extern int eject, listhex;
  70. extern unsigned address, bytes, errors, listleft, obj[], pagelen;
  71.  
  72. /*  The symbol table is a binary tree of variable-length blocks drawn    */
  73. /*  from the heap with the calloc() function.  The root pointer lives    */
  74. /*  here:                                */
  75.  
  76. static SYMBOL *sroot = NULL;
  77.  
  78. /*  Add new symbol to symbol table.  Returns pointer to symbol even if    */
  79. /*  the symbol already exists.  If there's not enough memory to store    */
  80. /*  the new symbol, a fatal error occurs.                */
  81.  
  82. SYMBOL *new_symbol(nam)
  83. char *nam;
  84. {
  85.     SCRATCH int i;
  86.     SCRATCH SYMBOL **p, *q;
  87.     void fatal_error();
  88.  
  89.     for (p = &sroot; (q = *p) && (i = strcmp(nam,q -> sname)); )
  90.     p = i < 0 ? &(q -> left) : &(q -> right);
  91.     if (!q) {
  92.     if (!(*p = q = (SYMBOL *)calloc(1,sizeof(SYMBOL) + strlen(nam))))
  93.         fatal_error(SYMBOLS);
  94.     strcpy(q -> sname,nam);
  95.     }
  96.     return q;
  97. }
  98.  
  99. /*  Look up symbol in symbol table.  Returns pointer to symbol or NULL    */
  100. /*  if symbol not found.                        */
  101.  
  102. SYMBOL *find_symbol(nam)
  103. char *nam;
  104. {
  105.     SCRATCH int i;
  106.     SCRATCH SYMBOL *p;
  107.  
  108.     for (p = sroot; p && (i = strcmp(nam,p -> sname));
  109.     p = i < 0 ? p -> left : p -> right);
  110.     return p;
  111. }
  112.  
  113. /*  Opcode table search routine.  This routine pats down the opcode    */
  114. /*  table for a given opcode and returns either a pointer to it or    */
  115. /*  NULL if the opcode doesn't exist.                    */
  116.  
  117. OPCODE *find_code(nam)
  118. char *nam;
  119. {
  120.     OPCODE *bsearch();
  121.  
  122.     static OPCODE opctbl[] = {
  123.     { TWOOP,        0x61,    "ADC"    },
  124.     { TWOOP,        0x21,    "AND"    },
  125.     { LOGOP,        0x06,    "ASL"    },
  126.     { INHOP,        0x0a,    "ASLA"    },
  127.     { RELBR,        0x90,    "BCC"    },
  128.     { RELBR,        0xb0,    "BCS"    },
  129.     { RELBR,        0xf0,    "BEQ"    },
  130.     { BITOP,        0x24,    "BIT"    },
  131.     { RELBR,        0x30,    "BMI"    },
  132.     { RELBR,        0xd0,    "BNE"    },
  133.     { RELBR,        0x10,    "BPL"    },
  134.     { INHOP,        0x00,    "BRK"    },
  135.     { RELBR,        0x50,    "BVC"    },
  136.     { RELBR,        0x70,    "BVS"    },
  137.     { INHOP,        0x18,    "CLC"    },
  138.     { INHOP,        0xd8,    "CLD"    },
  139.     { INHOP,        0x58,    "CLI"    },
  140.     { INHOP,        0xb8,    "CLV"    },
  141.     { TWOOP,        0xc1,    "CMP"    },
  142.     { CPXY,            0xe0,    "CPX"    },
  143.     { CPXY,            0xc0,    "CPY"    },
  144.     { INCOP,        0xc6,    "DEC"    },
  145.     { INHOP,        0xca,    "DEX"    },
  146.     { INHOP,        0x88,    "DEY"    },
  147.     { PSEUDO + ISIF,    ELSE,    "ELSE"    },
  148.     { PSEUDO,        END,    "END"    },
  149.     { PSEUDO + ISIF,    ENDI,    "ENDI"    },
  150.     { TWOOP,        0x41,    "EOR"    },
  151.     { PSEUDO,        EQU,    "EQU"    },
  152.     { PSEUDO,        FCB,    "FCB"    },
  153.     { PSEUDO,        FCC,    "FCC"    },
  154.     { PSEUDO,        FDB,    "FDB"    },
  155.     { PSEUDO + ISIF,    IF,    "IF"    },
  156.     { INCOP,        0xe6,    "INC"    },
  157.     { PSEUDO,        INCL,    "INCL"    },
  158.     { INHOP,        0xe8,    "INX"    },
  159.     { INHOP,        0xc8,    "INY"    },
  160.     { JUMP,            0x4c,    "JMP"    },
  161.     { CALL,            0x20,    "JSR"    },
  162.     { TWOOP,        0xa1,    "LDA"    },
  163.     { LDXY,            0xa2,    "LDX"    },
  164.     { LDXY,            0xa0,    "LDY"    },
  165.     { LOGOP,        0x46,    "LSR"    },
  166.     { INHOP,        0x4a,    "LSRA"    },
  167.     { INHOP,        0xea,    "NOP"    },
  168.     { TWOOP,        0x01,    "ORA"    },
  169.     { PSEUDO,        ORG,    "ORG"    },
  170.     { PSEUDO,        PAGE,    "PAGE"    },
  171.     { INHOP,        0x48,    "PHA"    },
  172.     { INHOP,        0x08,    "PHP"    },
  173.     { INHOP,        0x68,    "PLA"    },
  174.     { INHOP,        0x28,    "PLP"    },
  175.     { PSEUDO,        RMB,    "RMB"    },
  176.     { LOGOP,        0x26,    "ROL"    },
  177.     { INHOP,        0x2a,    "ROLA"    },
  178.     { LOGOP,        0x66,    "ROR"    },
  179.     { INHOP,        0x6a,    "RORA"    },
  180.     { INHOP,        0x40,    "RTI"    },
  181.     { INHOP,        0x60,    "RTS"    },
  182.     { TWOOP,        0xe1,    "SBC"    },
  183.     { INHOP,        0x38,    "SEC"    },
  184.     { INHOP,        0xf8,    "SED"    },
  185.     { INHOP,        0x78,    "SEI"    },
  186.     { PSEUDO,        SET,    "SET"    },
  187.     { TWOOP,        0x81,    "STA"    },
  188.     { STXY,            0x86,    "STX"    },
  189.     { STXY,            0x84,    "STY"    },
  190.     { INHOP,        0xaa,    "TAX"    },
  191.     { INHOP,        0xa8,    "TAY"    },
  192.     { PSEUDO,        TITL,    "TITL"    },
  193.     { INHOP,        0xba,    "TSX"    },
  194.     { INHOP,        0x8a,    "TXA"    },
  195.     { INHOP,        0x9a,    "TXS"    },
  196.     { INHOP,        0x98,    "TYA"    }
  197.     };
  198.  
  199.     return bsearch(opctbl,opctbl + (sizeof(opctbl) / sizeof(OPCODE)),nam);
  200. }
  201.  
  202. /*  Operator table search routine.  This routine pats down the        */
  203. /*  operator table for a given operator and returns either a pointer    */
  204. /*  to it or NULL if the opcode doesn't exist.                */
  205.  
  206. OPCODE *find_operator(nam)
  207. char *nam;
  208. {
  209.     OPCODE *bsearch();
  210.  
  211.     static OPCODE oprtbl[] = {
  212.     { REG,                'A',        "A"    },
  213.     { BINARY + LOG1  + OPR,        AND,        "AND"    },
  214.     { BINARY + RELAT + OPR,        '=',        "EQ"    },
  215.     { BINARY + RELAT + OPR,        GE,        "GE"    },
  216.     { BINARY + RELAT + OPR,        '>',        "GT"    },
  217.     { UNARY  + UOP3  + OPR,        HIGH,        "HIGH"    },
  218.     { BINARY + RELAT + OPR,        LE,        "LE"    },
  219.     { UNARY  + UOP3  + OPR,        LOW,        "LOW"    },
  220.     { BINARY + RELAT + OPR,        '<',        "LT"    },
  221.     { BINARY + MULT  + OPR,        MOD,        "MOD"    },
  222.     { BINARY + RELAT + OPR,        NE,        "NE"    },
  223.     { UNARY  + UOP2  + OPR,        NOT,        "NOT"    },
  224.     { BINARY + LOG2  + OPR,        OR,        "OR"    },
  225.     { BINARY + MULT  + OPR,        SHL,        "SHL"    },
  226.     { BINARY + MULT  + OPR,        SHR,        "SHR"    },
  227.     { REG,                'X',        "X"    },
  228.     { BINARY + LOG2  + OPR,        XOR,        "XOR"    },
  229.     { REG,                'Y',        "Y"    },
  230.     };
  231.  
  232.     return bsearch(oprtbl,oprtbl + (sizeof(oprtbl) / sizeof(OPCODE)),nam);
  233. }
  234.  
  235. static OPCODE *bsearch(lo,hi,nam)
  236. OPCODE *lo, *hi;
  237. char *nam;
  238. {
  239.     SCRATCH int i;
  240.     SCRATCH OPCODE *chk;
  241.  
  242.     for (;;) {
  243.     chk = lo + (hi - lo) / 2;
  244.     if (!(i = ustrcmp(chk -> oname,nam))) return chk;
  245.     if (chk == lo) return NULL;
  246.     if (i < 0) lo = chk;
  247.     else hi = chk;
  248.     }
  249. }
  250.  
  251. static int ustrcmp(s,t)
  252. char *s, *t;
  253. {
  254.     SCRATCH int i;
  255.  
  256.     while (!(i = toupper(*s++) - toupper(*t)) && *t++);
  257.     return i;
  258. }
  259.  
  260. /*  Buffer storage for line listing routine.  This allows the listing    */
  261. /*  output routines to do all operations without the main routine    */
  262. /*  having to fool with it.                        */
  263.  
  264. static FILE *list = NULL;
  265.  
  266. /*  Listing file open routine.  If a listing file is already open, a    */
  267. /*  warning occurs.  If the listing file doesn't open correctly, a    */
  268. /*  fatal error occurs.  If no listing file is open, all calls to    */
  269. /*  lputs() and lclose() have no effect.                */
  270.  
  271. void lopen(nam)
  272. char *nam;
  273. {
  274.     FILE *fopen();
  275.     void fatal_error(), warning();
  276.  
  277.     if (list) warning(TWOLST);
  278.     else if (!(list = fopen(nam,"w"))) fatal_error(LSTOPEN);
  279.     return;
  280. }
  281.  
  282. /*  Listing file line output routine.  This routine processes the    */
  283. /*  source line saved by popc() and the output of the line assembler in    */
  284. /*  buffer obj into a line of the listing.  If the disk fills up, a    */
  285. /*  fatal error occurs.                            */
  286.  
  287. void lputs()
  288. {
  289.     SCRATCH int i, j;
  290.     SCRATCH unsigned *o;
  291.     void check_page(), fatal_error();
  292.  
  293.     if (list) {
  294.     i = bytes;  o = obj;
  295.     do {
  296.         fprintf(list,"%c  ",errcode);
  297.         if (listhex) {
  298.         fprintf(list,"%04x  ",address);
  299.         for (j = 4;